Class 的继承

与 es5 继承机制的区别

ES6 规定,子类必须在 constructor() 方法中调用 super(),否则就会报错

js
class Point { /* ... */ }

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y) // 必须调用
    this.color = color
  }

  toString() {
    return `${this.color} ${super.toString()}` // 调用父类的toString()
  }
}

私有的属性和方法的继承

父类所有的属性和方法,都会被子类继承,除了私有的属性和方法

js
class Foo {
  #p = 1
  getP() {
    return this.#p
  }
}

class Bar extends Foo {
  constructor() {
    super()
    console.log(this.getP()) // 1
    // this.#p // 报错
    // super.#p // 报错
  }
}

静态的属性和方法的继承

通过浅拷贝实现继承

js
class A {
  static foo = 100
}
class B extends A {
  constructor() {
    super()
    B.foo--
  }
}

const b = new B()
B.foo // 99
A.foo // 100
js
class A {
  static foo = { n: 100 }
}

class B extends A {
  constructor() {
    super()
    B.foo.n--
  }
}

const b = new B()
B.foo.n // 99
A.foo.n // 99

prototype 属性和 __proto__ 属性

大多数浏览器的 ES5 实现之中,每一个对象都有 __proto__ 属性,指向对应的构造函数的 prototype属性。

Class 作为构造函数的语法糖,同时有 prototype 属性和 __proto__ 属性,因此同时存在两条继承链

  • 子类的 __proto__ 属性,表示构造函数的继承,总是指向父类

    与 es5 的不同
  • 子类的 prototype 属性的 __proto__ 属性,表示方法的继承,总是指向父类的 prototype 属性

js
class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
js
class Point { /* ... */ }
class ColorPoint extends Point { /* ... */ }
Object.getPrototypeOf(ColorPoint) === Point // TODO true